package com.logic.landseaserver.models.rerent.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import com.logic.landseaserver.common.util.ConstantChar;
import com.logic.landseaserver.common.util.StringTools;
import com.logic.landseaserver.domain.*;
import com.logic.landseaserver.models.prepayment.service.PrepaymentService;
import com.logic.landseaserver.persistence.read.*;
import com.logic.landseaserver.persistence.write.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.logic.common.exception.BusinessException;
import com.logic.common.security.SecurityUtils;
import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.LandeaConstants.ProduceType;
import com.logic.landseaserver.common.LandseaErrorMessageEnum;
import com.logic.landseaserver.common.enums.BTypeEnum;
import com.logic.landseaserver.common.enums.BillStatusEnum;
import com.logic.landseaserver.common.enums.BillTypeEnum;
import com.logic.landseaserver.common.enums.ContractStatusCodeEnum;
import com.logic.landseaserver.common.enums.LeaseCodeEnum;
import com.logic.landseaserver.common.enums.SystemCodeEnum;
import com.logic.landseaserver.common.exception.LandseaBusinessException;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.util.DateUtil;
import com.logic.landseaserver.models.authcode.service.CouponUsedService;
import com.logic.landseaserver.models.independent.service.BillIndependentService;
import com.logic.landseaserver.models.payment.PaymentConstant;
import com.logic.landseaserver.models.payment.service.PaymentService;
import com.logic.landseaserver.service.IBillPaymentService;
import com.logic.landseaserver.service.IBillService;
import com.logic.landseaserver.service.ICheckFeeListService;
import com.logic.landseaserver.service.IContractOfflineService;
import com.logic.landseaserver.service.IContractService;
import com.logic.landseaserver.service.ICustomer;
import com.logic.landseaserver.service.IOffrentPreBill;
import com.logic.landseaserver.service.IProjectAppartment;
import com.logic.landseaserver.service.bill.rerent.OverBillService;
import com.logic.landseaserver.ws.dto.BillPaymentDTO;
import com.logic.landseaserver.ws.dto.CheckFeeListDTO;
import com.logic.landseaserver.ws.dto.ContractDTO;
import com.logic.landseaserver.ws.dto.QueryCouponUesdDTO;
import com.logic.landseaserver.ws.dto.UrgentDTO;
import com.logic.landseaserver.ws.request.ContractNeedDelReq;
import com.logic.landseaserver.ws.request.CreateOffLineContractsReq;
import com.logic.landseaserver.ws.request.RoomDetailReq;
import com.logic.system.service.IConfigurationService;

/**
 * Created by Junny on 2017/11/23.
 * M3 续租
 */
@Service
public class ReRentService implements IReRentService{
    private static final Logger logger = LoggerFactory.getLogger(ReRentService.class);

    @Autowired
    private ICustomer customerService;
    @Autowired
    private IProjectAppartment roomService;
    @Autowired
    private CouponUsedService couponUsedService;
    @Autowired
    private BalanceSheetRecordReadMapper balanceSheetRecordReadMapper;
    @Autowired
    private IContractOfflineService contractOfflineService;
    @Autowired
    private ContractWriteMapper contractWriteMapper;
    @Autowired
    private IBillService billService;
    @Autowired
    private IContractService contractService;
    @Autowired
    private ContractReadMapper contractReadMapper;
    @Autowired
    private IOffrentPreBill offrentPreBillService;
    @Autowired
    private OverBillService overBillService;
    @Autowired
    private BillDetailWriteMapper billDetailWriteMapper;
    @Autowired
    private BillWriteMapper billWriteMapper;
    @Autowired
    private IBillPaymentService billPayService;
    @Autowired
    private CheckListWriteMapper checkListWriteMapper;
    @Autowired
    private CheckFeeListWriteMapper checkFeeListWriteMapper;
    @Autowired
    private ICheckFeeListService checkFeeListService;
    @Autowired
    private BillDetailReadMapper billDetailReadMapper;
    @Autowired
    private CheckFeeListReadMapper checkFeeListReadMapper;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private BillIndependentService billIndependentService;
    @Autowired
    private UrgentReadMapper urgentReadMapper;
    @Autowired
    private UrgentWriteMapper urgentWriteMapper;
    @Autowired
    private PrepaymentService prepaymentService;
    @Autowired
    private RoomReadMapper roomReadMapper;
    @Autowired
    private IConfigurationService configurationService;
    @Autowired
    private BillPaymentWriteMapper billPaymentWriteMapper;

    @Autowired
    private CustomerCardWriteMapper customerCardWriteMapper;

    @Autowired
    private CustomerCardReadMapper customerCardReadMapper;


    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = {BusinessException.class,
            LandseaException.class,Exception.class})
    public Integer createReRent(CreateOffLineContractsReq rqObj)throws LandseaException,BusinessException{
        Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
        if (systemId == null) {
            throw LandseaException.createException(LandseaErrorMessageEnum.TOKEN_IS_NULL);
        }
        validateForInsert(rqObj);
        //取原始合同
        Contract oldContract = contractReadMapper.selectByPrimaryKey(rqObj.getContractId());
        if(!oldContract.getStatus().equals(ContractStatusCodeEnum.SIGN.getCode())){
            throw LandseaException.createException(LandseaErrorMessageEnum.RERENT_CONTRACT_STATUS_ERROR);
        }
        List<BillDetail> lastPayBillDts = offrentPreBillService.queryLastPayBill(rqObj.getContractId());
        //获取上次房租服务费缴费日期
        Optional<BillDetail> billHourse = lastPayBillDts.stream().filter(e -> e.getType().equals(BillTypeEnum.CTBI8.getCode())).findFirst();
        if (!billHourse.isPresent()) {
            throw LandseaException.createException(LandseaErrorMessageEnum.OFFRENT_HOURSE_BILL_ERROR);
        }
        if(DateUtil.compareTime(billHourse.get().getDateEnd(),oldContract.getOutDate())!=0){
            throw LandseaException.createException(LandseaErrorMessageEnum.RERENT_HOURSEBILL_NO_PAY_OVER);
        }

        Map<String,Object> queryParam = new HashMap<String,Object>();
        queryParam.put("contractId", rqObj.getContractId());
        queryParam.put("checkType", LandeaConstants.CheckType.IN_COMING);
        List<CheckFeeListDTO> feeList = checkFeeListReadMapper.selectByContractIdAndCheckType(queryParam);
        if(feeList.size()==0){
            throw LandseaException.createException(LandseaErrorMessageEnum.OFFRENT_CHECKIN_CHECKFILE_NOT_EXIST);
        }
        Integer userId = rqObj.getUserId();
        //获取当前用户版本
        CustomerVersion customer = customerService.getNewVersion(userId);
        String version = customer==null ? "" : customer.getVersionNumber();

        RoomDetailReq aprt = roomService.searchRoomInfo(rqObj.getRoomId());
        if (aprt == null) {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_APRT_ISNULL);
        }
        contractOfflineService.calculationMonthRent(aprt, rqObj, null);

        // 新建合同
        Contract ctc = CreateOffLineContractsReq.convertDTOtoContract(rqObj);
        ctc.setUserId(userId);
        // 房间信息
        ctc.setProjectId(aprt.getPrjId());
        ctc.setOffLine(true);
        ctc.setUserVersion(version);
        ctc.setOriginalWaterDeposit(aprt.getProject().getDepositWater());
        ctc.setRentType(LandeaConstants.ReRentType.RERENT);
        ctc.setSourceRentType(LandeaConstants.ReRentType.RERENT);
        ctc.setOriginalCId(rqObj.getContractId());

        ctc.updateCommonInfo(systemId);

        //查看是否有授权码
        couponUsedService.checkUesdAuthCode(LandeaConstants.QueryUesdCodeType.CONTRACT,userId,rqObj.getAuthCodes());

        // 设置收取滞纳金、门锁时长
        Integer lateFeeDay = configurationService.getIntegerValue("SYS_TIM_FOR_LAT_FEE");
        Integer payLastDay = configurationService.getIntegerValue("PAY_LAST_DAY_TIME");
        ctc.setLatefeeDay(lateFeeDay);
        ctc.setLastPayDay(payLastDay);
        
        contractWriteMapper.insertSelective(ctc);

        //修改原始合同
        Contract oldContractMod = new Contract();
        oldContractMod.setId(rqObj.getContractId());
        oldContractMod.setRentType(LandeaConstants.ReRentType.RERENT);
        oldContractMod.updateCommonInfo(systemId);
        contractWriteMapper.updateByPrimaryKeySelective(oldContractMod);

        //同步A合同的紧急联系人
        List<UrgentDTO> urgentDTOs = urgentReadMapper.queryDetailByContractId(rqObj.getContractId(), null);
        if(urgentDTOs.size()>0){
            UrgentDTO relativeUser = urgentDTOs.get(0);
            if (relativeUser != null) {
                Urgent urgent = new Urgent();
                urgent.setUrgentName(relativeUser.getUrgentName());
                urgent.setUrgentPhone(relativeUser.getUrgentPhone());
                urgent.setContractId(ctc.getId());
                urgent.setUrgentRelation(relativeUser.getUrgentRelation());
                urgent.updateCommonInfo(systemId);
                urgentWriteMapper.insertSelective(urgent);
            }
        }
        //同步A合同的银行卡信息
        if(rqObj.getCardUserName()!=null){
            CustomerCard customerCard =CreateOffLineContractsReq.convertDTOtoCustomerCard(rqObj);
            customerCard.setSourceId(ctc.getId());
            customerCard.updateCommonInfo(systemId);
            customerCardWriteMapper.insertSelective(customerCard);
        }
        if (ctc.getId() != null) {
            try {
                billService.createFirstBill(ctc.getId(),rqObj.getAuthCodes());
                // 生成pdf
                contractService.createPdf(ctc.getId());
            } catch (LandseaException e) {
                logger.error("生成pdf异常", e);
                throw new LandseaBusinessException(e.getErrorEnum());
            } catch (Exception e) {
                logger.error("生成pdf异常", e);
            }
        }
        return ctc.getId();
    }
    private void validateForInsert(CreateOffLineContractsReq req)throws LandseaBusinessException{
        if (req.getContractId() == null ) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_CONTRACTID_ISNULL);
        }
        if (req.getUserId() == null ) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_USERID_ISNULL);
        }
        if (req.getProjectId() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECTID_ISNULL);
        }

        if (req.getRoomId() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ROOMID_ISNULL);
        }

        if (StringUtils.isEmpty(req.getPaymentMode())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PAYMENTMODE_ISNULL);
        }

        if (StringUtils.isEmpty(req.getLease())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_LEASE_ISNULL);
        }

        if (req.getInDate() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_INDATE_ISNULL);
        }

        if (req.getOutDate() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_OUTDATE_ISNULL);
        }
        //如果租期为其他 leaseM   leaseD 不能为空
        if(req.getLease().equals(LeaseCodeEnum.LEAS99.getCode())){
            if(req.getLeaseM()==null || req.getLeaseD()==null){
                throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_LEASEMD_INDATE_INVALID);
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaBusinessException.class, Exception.class})
    public void createOverList(Integer contractId) throws LandseaException {
        Date reRentDate = new Date();
        //查询该合同是否存在
        Contract contract = contractReadMapper.selectByPrimaryKey(contractId);
        if (contract == null) {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_IS_NULL);
        }
        if(!StringUtils.isEmpty(contract.getRentStatus())){
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_RENTTYPE_ERROR);
        }
        List<BillDetail> lastPayBillDts = offrentPreBillService.queryLastPayBill(contract.getId());
        //获取上次房租服务费缴费日期
        Optional<BillDetail> billHourse = lastPayBillDts.stream().filter(e -> e.getType().equals(BillTypeEnum.CTBI8.getCode())).findFirst();
        if (!billHourse.isPresent()) {
            throw LandseaException.createException(LandseaErrorMessageEnum.OFFRENT_HOURSE_BILL_ERROR);
        }
        if(DateUtil.compareTime(billHourse.get().getDateEnd(),contract.getOutDate())!=0){
            throw LandseaException.createException(LandseaErrorMessageEnum.RERENT_HOURSEBILL_NO_PAY_OVER);
        }
        //释放结转单授权码使用记录
        PreOffrentBill preOffrentBill = offrentPreBillService.queryPreBillByContractId(contractId);
        //判断是否存在有效的预结算单，如存在则删除
        offrentPreBillService.deletePreBillByContractId(contract.getId());
        //撤销结转单的授权码使用记录
        if(preOffrentBill!=null){
            couponUsedService.deleteCouponUesd(preOffrentBill.getId(), LandeaConstants.QueryUesdCodeType.OFFRENT);
        }
        //新增结转单
        Integer preBillId =overBillService.createOverBill(contract);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaException.class, Exception.class})
    public void synOverList(Integer contractId) throws LandseaException {
        Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
        if (systemId == null) {
            throw LandseaException.createException(LandseaErrorMessageEnum.TOKEN_IS_NULL);
        }
        Date nowDate = new Date();
        //查询该合同是否存在
        Contract contract = contractReadMapper.selectByPrimaryKey(contractId);
        if (contract == null) {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_IS_NULL);
        }
        //查询A合同是否存在
        Contract orgContract = contractReadMapper.selectByPrimaryKey(contract.getOriginalCId());
        if (StringUtils.isEmpty(orgContract.getRentStatus())) {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_RENTSTATUS_ERROR);
        }
        //查询B合同是否已存在结转
        Bill parBill = billService.queryFirstBill(contractId);
        List<BillDetail> firstBills = new ArrayList<>();
        if(parBill!=null){
            firstBills = billDetailReadMapper.getBillDetail(parBill.getId());
            if(firstBills.size()==0){
                throw LandseaException.createException(LandseaErrorMessageEnum.FIRST_BILLDETAILS_NOT_EXIST_CONTRACT);
            }
            List<BillDetail> billDetails =  firstBills.stream().filter(e->e.getOverlistFlag()!=0).collect(Collectors.toList());
            if(billDetails.size()>0){
                throw LandseaException.createException(LandseaErrorMessageEnum.FIRST_BILLDETAILS_OVERLIST);
            }
        }else{
            throw LandseaException.createException(LandseaErrorMessageEnum.FIRST_BILL_NOT_EXIST_CONTRACT);
        }

        if (StringUtils.isEmpty(orgContract.getRentStatus())) {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_RENTSTATUS_ERROR);
        }
        
        try
        {
            //查询A合同结转单
            PreOffrentBill preOffrentBill =  offrentPreBillService.queryPreBillByContractId(contract.getOriginalCId());
            if(preOffrentBill!=null){
                String hourseNum = "";
                Room room = roomReadMapper.selectByPrimaryKey(contract.getRoomId());
                hourseNum = room.getHouseNum();
                List<BillDetail> billDetails = new ArrayList<>();
                List<PreOffrentDetailBill> details =
                        offrentPreBillService.queryPreBillDetailByPreId(preOffrentBill.getId(),LandeaConstants.OffRentBillType.OFFRENTBILL);
                if(details!=null){
                    for(PreOffrentDetailBill pBill:details){
                        //如果是房屋押金和水费押金，则入billpayment表和独立账单表
                        if(pBill.getPreType().equals(BillTypeEnum.CTBI11.getCode()) || pBill.getPreType().equals(BillTypeEnum.CTBI10.getCode())){
                            createPreBillPayment(pBill,orgContract,hourseNum);
                        }
                    }
                    //获取需要结转的费项
                    List<PreOffrentDetailBill> positives = details.stream().filter(e->e.getBillAmount()>0).collect(Collectors.toList());
                    List<PreOffrentDetailBill> authDetailBill =  details.stream().filter(e->e.getCouponFlag()).collect(Collectors.toList());
                    //结转应缴金额
                    Double totalPrice = 0.0;
                    if(positives!=null){
                      //  String billNo = fstBill.getContractNo()+"01";
                       // Integer detailNum = billDetails.size();
                        for(PreOffrentDetailBill dtBill: positives){
                         //   detailNum++;
                         //   String detailNo = billNo + String.format("%02d", detailNum);
                            BillDetail bdt = billService.convertPreDetailToBillDetail(dtBill);
                            Double billMoney = bdt.getMoney();
                            if(authDetailBill.size()>0){
                                List<PreOffrentDetailBill> typeCodes= authDetailBill.stream().filter(e->e.getPreType().equals(dtBill.getPreType())).collect(Collectors.toList());
                                Double authMoney = 0.0;
                                for(PreOffrentDetailBill pdb:typeCodes){
                                    authMoney = authMoney+pdb.getBillAmount();
                                }
                                billMoney = billMoney+authMoney;
                                bdt.setMoney(billMoney);
                            }
                            bdt.setBillId(parBill.getId());
                           // bdt.setDetailNo(detailNo);
                            bdt.setOverlistFlag(LandeaConstants.ReRentFlag.RERENT);
                            bdt.setOriginalCId(contract.getOriginalCId());
                            bdt.setRemark(orgContract.getContractNo()+ConstantChar.sys_over_contract);
                            bdt.updateCommonInfo(systemId);
                            billDetails.add(bdt);
                            totalPrice = totalPrice+billMoney;
                        }
                    }

                    if (billDetails.size() > 0) {
                        for (BillDetail b : billDetails)
                        {
                            billDetailWriteMapper.insertSelective(b);
                        }
                    }
                    //修改parBill
                    Double totalBillMoney = parBill.getReceivableMoney()+totalPrice;
                    parBill.setReceivableMoney(totalBillMoney);
                    //获取A合同的房屋押金和水费押金
                    Double totalDeposit = orgContract.getWaterDeposit()+orgContract.getDeposit();
                    Double payMoney = 0.0;
                    if(totalDeposit.compareTo(totalBillMoney)<=0){
                        //直接抵扣
                        parBill.setAmountReceived(totalDeposit);
                        //新增支付记录
                        createHoursePayment(parBill,orgContract.getDeposit(),nowDate);
                        createWaterPayment(parBill,orgContract.getWaterDeposit(),nowDate);
                        parBill.setBillStatus(BillStatusEnum.BIST1.getCode());
                        billWriteMapper.updateByPrimaryKeySelective(parBill);
                        // 部分支付的情况,处理支付账单
                        for (BillDetail billTail : billDetails)
                        {
                            BalanceSheetRecord balanceSheetRecord = buildFirstBillBalanceRecord(contract, parBill, billTail, false, nowDate,hourseNum);
                            billIndependentService.insertBalanceSheet(balanceSheetRecord);
                        }
                        payMoney = totalDeposit;
                    }else{
                        Double saveMoney = totalDeposit-totalBillMoney;
                        //此次可抵扣金额
                        //房租抵扣金额
                        if(orgContract.getDeposit().compareTo(totalBillMoney)>=0){//房屋押金族已抵扣应缴
                            createHoursePayment(parBill,totalBillMoney,nowDate);
                        }else{//需加上水费押金
                            createHoursePayment(parBill,orgContract.getDeposit(),nowDate);
                            createHoursePayment(parBill,totalDeposit-saveMoney-orgContract.getDeposit(),nowDate);
                        }
                        parBill.setAmountReceived(totalBillMoney);
                        //TOOD Junny 存入余额
                        prepaymentService.addAccountBalanceMoney4Rerent(contract.getUserId(),contract.getRoomId(),saveMoney,nowDate);
                        parBill.setBillStatus(BillStatusEnum.BIST2.getCode());
                        billWriteMapper.updateByPrimaryKeySelective(parBill);
                        // 支付成功后处理
                        contractService.updateAfterPay(contractId, parBill.getId(), nowDate);
                        billService.updateMontlyOrgContract(contractId, parBill.getId());
                        // 全部支付的情况
                        // 支付成功-更新独立账单
                        for (BillDetail billTail : billDetails){
                            BalanceSheetRecord balanceSheetRecord = buildFirstBillBalanceRecord(contract, parBill, billTail, true, nowDate,hourseNum);
                            billIndependentService.insertBalanceSheet(balanceSheetRecord);
                        }
                        for (BillDetail billTail : firstBills) {
                            billIndependentService.firUpdateBalanceSheet(billTail.getBillId(),
                                    contract.getContractNo(),billTail,nowDate);
                        }
                        payMoney=totalBillMoney;
                    }
                    List<BillDetail> allDetailList = new ArrayList<BillDetail>();
                    allDetailList.addAll(billDetails);
                    allDetailList.addAll(firstBills);
                    paymentService.reRentFirstBillPaidProcess(payMoney, allDetailList);
                }

                //如果是逾期续租，则直接将A合同改为已结束
                if(preOffrentBill.getOffrentType().equals(LandeaConstants.OffrentType.DELAY_RENT)){
                    Contract contractA = new Contract();
                    contractA.setId(orgContract.getId());
                    contractA.setStatus(ContractStatusCodeEnum.END.getCode());
                    contractA.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
                    contractWriteMapper.updateByPrimaryKeySelective(contractA);
                }
            }
            //同步入住交割单
           // checkFeeListService.synFeeList(contractId);
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e2)
        {
            logger.error("synOverList error.", e2);
            throw LandseaException.createException(LandseaErrorMessageEnum.FIRST_BILLDETAILS_OVERLIST_ERROR, e2);
        }
    }

    private void createWaterPayment(Bill parBill,Double depositPrice, Date date) throws LandseaException {
        BillPaymentDTO waterPay = new BillPaymentDTO();
        waterPay.setBillId(parBill.getId());
        waterPay.setPayType(PaymentConstant.PayChannel.WATER_DEPOSIT);
        waterPay.setTime(date);
        waterPay.setMoney(depositPrice);
        waterPay.setTransactionNo("");
        waterPay.setBillType(BTypeEnum._BT1.getCode());
        waterPay.setStatus(SystemCodeEnum.PAY_TRUE.getCode());
        waterPay.setNeedCheckMoney(false);
        billPayService.insertBillPaymentDTO(waterPay);
    }

    private void createHoursePayment(Bill parBill, Double waterPrice, Date date) throws LandseaException {
        BillPaymentDTO hoursePay = new BillPaymentDTO();
        hoursePay.setBillId(parBill.getId());
        hoursePay.setPayType(PaymentConstant.PayChannel.HOURSEDEPOSIT);
        hoursePay.setTime(date);
        hoursePay.setMoney(waterPrice);
        hoursePay.setTransactionNo("");
        hoursePay.setBillType(BTypeEnum._BT1.getCode());
        hoursePay.setStatus(SystemCodeEnum.PAY_TRUE.getCode());
        hoursePay.setNeedCheckMoney(false);
        billPayService.insertBillPaymentDTO(hoursePay);
    }
    private void createPreBillPayment(PreOffrentDetailBill dtBill,Contract contract,String hourseNum) throws LandseaException {
        Date nowD = new Date();
        BillPayment billPay = new BillPayment();
        billPay.setBillId(dtBill.getId());
        //房屋押金
        if(dtBill.getPreType().equals(BillTypeEnum.CTBI11.getCode())){
            billPay.setPayType(PaymentConstant.PayChannel.HOURSEDEPOSIT);
        }else if(dtBill.getPreType().equals(BillTypeEnum.CTBI10.getCode())){ //水费押金
            billPay.setPayType(PaymentConstant.PayChannel.WATER_DEPOSIT);
        }
        billPay.setTime(nowD);
        billPay.setMoney(dtBill.getBillAmount());
        billPay.setTransactionNo("");
        billPay.setBillType(BTypeEnum._BT7.getCode());
        billPay.setStatus(SystemCodeEnum.PAY_TRUE.getCode());
        billPay.setNeedCheckMoney(false);
        billPay.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
        billPaymentWriteMapper.insertSelective(billPay);

        //往独立账单放入一条
        BalanceSheetRecord record = new BalanceSheetRecord();
        record.setContractNo(contract.getContractNo());
        record.setProjectId(contract.getProjectId());
        record.setRoomId(contract.getRoomId());
        record.setContractId(contract.getId());

        record.setBillId(dtBill.getId());
        record.setBillMonth(DateUtil.getInstence().convertYM(nowD));
        record.setBillName(ConstantChar.TRANS_OVER_BILL);
        record.setBillType(BTypeEnum._BT7.getCode());

        record.setReceivableMoney(dtBill.getBillAmount());
        record.setAmountReceived(dtBill.getBillAmount());
        record.setBillStatus(BillStatusEnum.BIST2.getCode());
        record.setPayTime(nowD);

        record.setExpenditureCode(dtBill.getPreType());

        record.setEndTime(dtBill.getDateEnd());
        record.setStartTime(dtBill.getDateBegin());
        record.setHouseNum(hourseNum);

        String expendZh = StringTools.getEmunName(dtBill.getPreType());
        record.setExpenditure(expendZh);
        record.setMark(contract.getContractNo()+"续租"+expendZh+"结转");
        record.setProduceType(ProduceType.PAY);
        billIndependentService.insertBalanceSheet(record);
    }

    @Override
    public void createPreBill(Integer contractId) throws LandseaException {
        Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
        if (systemId == null) {
            throw LandseaException.createException(LandseaErrorMessageEnum.TOKEN_IS_NULL);
        }
        //查询该合同是否存在
        Contract contract = contractReadMapper.selectByPrimaryKey(contractId);
        if (contract == null) {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_IS_NULL);
        }
        //查询是否是续租合同
        if(contract.getRentType()!=null){
            if(contract.getRentType().equals(LandeaConstants.ReRentType.RERENT)){
                if(DateUtil.compareTime(contract.getInDate(),new Date())>0){//未到入住日退房
                    //A->直接变成已结束
                    Contract oContract = new Contract();
                    oContract.setId(contract.getOriginalCId());
                    oContract.setStatus(ContractStatusCodeEnum.END.getCode());
                    oContract.updateCommonInfo(systemId);
                    contractWriteMapper.updateByPrimaryKeySelective(oContract);
                }
            }else{
                logger.info("并非续租合同");
                return;
            }
        }
        else{
            logger.info("并非续租合同");
            return;
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,  rollbackFor = {LandseaException.class, Exception.class})
    public boolean cancelReRent(Integer contractId) throws LandseaException {
        //查询原合同是否存在
        Contract contract = contractReadMapper.selectByPrimaryKey(contractId);
        if (contract == null) {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_IS_NULL);
        }
        ContractDTO rerentContract = contractReadMapper.queryReRentContractDetail(contractId);
        if(rerentContract!=null){
            Bill parBill = billService.queryFirstBill(rerentContract.getId());
            if(parBill.getPayWithMoney().intValue()==1){//存在过非抵扣的支付
                throw LandseaException.createException(LandseaErrorMessageEnum.DELETE_CONTRACT_HAS_PAY);
            }
            if(rerentContract.getIsChapter()){
                throw LandseaException.createException(LandseaErrorMessageEnum.RERENT_CONTRACTB_IS_CHAPTER);
            }
        }else{
            return true;
           // throw LandseaException.createException(LandseaErrorMessageEnum.RERENT_CONTRACTB_IS_NOTEXSIT);
        }

      /*  if (!contract.getStatus().equals(ContractStatusCodeEnum.SIGN.getCode())) {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_STATUS_IS_ERROR);
        }*/
        boolean result=true;
        //撤销退房交割单
        checkListWriteMapper.cancelCheckList(contractId, LandeaConstants.CheckType.UN_RENT);
        checkFeeListWriteMapper.cancelCheckFeeList(contractId, LandeaConstants.CheckType.UN_RENT);
        //撤销结转单
        offrentPreBillService.cancelPreBill(contractId);
        PreOffrentBill preOffrentBill = offrentPreBillService.queryPreBillByContractId(contractId);
        //撤销结转单的授权码使用记录
        if(preOffrentBill!=null){
            couponUsedService.deleteCouponUesd(preOffrentBill.getId(), LandeaConstants.QueryUesdCodeType.OFFRENT);
        }
        //撤销续租标识
        contractWriteMapper.updateRentTypeNull(rerentContract.getOriginalCId());
        //撤销同步的运营数据
        checkFeeListService.deleteSysFeeListToExpenses(contractId, LandeaConstants.CheckType.UN_RENT);
        //删除续租B合同
        List<ContractNeedDelReq> contractList = new ArrayList<ContractNeedDelReq>();
        ContractNeedDelReq req = new ContractNeedDelReq();
        req.setRoomId(rerentContract.getRoomId());
        req.setId(rerentContract.getId());
        contractList.add(req);
        // 删除账单
        billService.deleteNoPayBill(contractList);
        // 删除合同
        contractService.deleteNoPayContracts(contractList);
        // 根据合同删除独立账单
        contractService.deleteBalanceByContract(contractList);
        //删除授权码使用记录
        couponUsedService.deleteCouponUesd(rerentContract.getId(), LandeaConstants.QueryUesdCodeType.CONTRACT);
        //TOOD Junny saveMoney 预付款结转复原
        return result;
    }

    @Override
    public Object queryReRentContract(Integer contractId) {
        ContractDTO contractDTO = contractReadMapper.queryReRentContractDetail(contractId);
        if(contractDTO==null){
            return null;
        }
        //查询授权码使用信息
        HashMap map= new HashMap();
        map.put("mainId",contractDTO.getId());
        map.put("mainType",LandeaConstants.QueryUesdCodeType.CONTRACT);
        List<QueryCouponUesdDTO> codes= couponUsedService.querypPersonalCouponList(map);
        contractDTO.setAuthCodes(codes);
        //查询银行卡信息
        contractDTO.setCustomerCardDTO(customerCardReadMapper.queryCardInfo(map));
        return contractDTO;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,  rollbackFor = {Exception.class})
    public void confirmRerent(Integer contractId) {
        Contract contract = new Contract();
        contract.setId(contractId);
        contract.setRentStatus(LandeaConstants.ReRentType.RERENT);
        contract.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
        contractWriteMapper.updateByPrimaryKeySelective(contract);
        //其余费项->已支付
        //monthlyBillWriteMapper.updateMonthlyBillStatus(contractId,null);
        //同步checkFees 至 运营数据表
        //checkFeeListService.sysFeeListToExpenses(contractId, LandeaConstants.CheckType.UN_RENT);
    }

    private BalanceSheetRecord buildFirstBillBalanceRecord(Contract contract, Bill parBill, BillDetail billTail, boolean isPaid, Date date,String hourseNum)
    {
        // 往balanceSheet中加备份
        BalanceSheetRecord record = new BalanceSheetRecord();
        record.setContractNo(contract.getContractNo());
        record.setProjectId(contract.getProjectId());
        record.setRoomId(contract.getRoomId());
        record.setContractId(contract.getId());
        
        record.setBillId(parBill.getId());
        record.setBillMonth(parBill.getBillMonth());
        record.setBillName(parBill.getName());
        record.setBillType(LandeaConstants.BillType.FIRST_BILL);
        
        if (isPaid)
        {
            record.setAmountReceived(billTail.getMoney());
            record.setBillStatus(BillStatusEnum.BIST2.getCode());
            record.setPayTime(date);
        }
        else
        {
            record.setAmountReceived(0.00d);
            record.setBillStatus(BillStatusEnum.BIST3.getCode());
        }
        
        record.setExpenditureCode(billTail.getType());
        record.setReceivableMoney(billTail.getMoney());
        record.setEndTime(billTail.getDateEnd());
        record.setStartTime(billTail.getDateBegin());
        record.setHouseNum(hourseNum);
        record.setMark(billTail.getRemark());

        // 如果是授权码
        String expenditure = balanceSheetRecordReadMapper.selectExpenditure(billTail.getType());
        if (billTail.getCouponFlag())
        {
            record.setExpenditure(billIndependentService.getAuthCodeBillType(billTail.getType(), expenditure));
            record.setProduceType(ProduceType.AUTHCODE);
            
        }
        else
        {
            record.setExpenditure(expenditure);
            record.setProduceType(ProduceType.PAY);
        }
        
        return record;
    }
}
